<?php
class Apps_Form extends Zend_Form {
    private $_request;
    private $_response;

    protected $_lockMakeup = false;

    protected $_decoratorForm;
    protected $_decoratorFormDisplayGroups;
    protected $_decoratorFormSubForms;
    protected $_decoratorFormElements;

    protected $_actionGroups = array();

    public function removeFormTag() {
        $this->removeDecorator('f');
        return $this;
    }

    // GET MAKEUP DECORATOR
    public function getMakeupDecoratorForm() {
        if(!($d = $this->_decoratorForm)) {
            $this->_decoratorForm = $d = array(
                array('decorator' => array('fe' => 'FormElements'),
					  'options'   => null),
                array('decorator' => array('f'  => 'Form'),
                	  'options'   => array('class' => 'form-horizontal')) // Twitter-Bootstrap
            );
        }
        return $d;
    }
    public function getMakeupDecoratorFormDisplayGroups() {
        if(!($d = $this->_decoratorFormDisplayGroups)) {
            $this->_decoratorFormDisplayGroups = $d = array(
                array('decorator' => array('fe' => 'FormElements'),
                	  'options'   => null),
                array('decorator' => array('fs' => 'Fieldset'),
                      'option'    => null)
            );
        }
        return $d;
    }
    public function getMakeupDecoratorFormSubForms() {
        if(!($d = $this->_decoratorFormSubForms)) {
            $this->_decoratorFormSubForms = $d = array(
            array('decorator' => array('fe' => 'FormElements'),
            	  'options'   => null),
            array('decorator' => array('fs' => 'Fieldset'),
                  'option'    => null)
            );
        }
        return $d;
    }
    public function getMakeupDecoratorFormElements() {
        if(!($d = $this->_decoratorFormElements)) {
            $this->_decoratorFormElements = $d = array(
            array('decorator' => array('v' => 'ViewHelper'),
                           'options'   => null),

            array('decorator' => array('d' => 'Description'),
                           'options'   => array('tag'   => 'p',
                        						'class' => 'help-block')),

            array('decorator' => array('e' => 'Errors'),
                           'options'   => null),

            array('decorator' => array('h' => 'HtmlTag'),
                           'options'   => array('tag'   => 'div',
                           						'class' => 'controls')),

            array('decorator' => array('l' => 'Label'),
                     	   'options'   => array('class' 		 => 'control-label',
												'requiredSuffix' => ' <span style="color:red">*</span>',
                     	                        'escape' 		 => false)),

            array('decorator' => array('w' => 'HtmlTag'),
                           'options'   => array('tag'   => 'div',
                           						'class' => 'control-group'))
            );
        }
        return $d;
    }

    /**
     * Lock Makeup trigger - typically used in to-be-extend form
     * @param bool $lock
     * @return Apps_Form
     */
    public function lockMakeup($lock=true) {
        $this->_lockMakeup = (bool)$lock;
        return $this;
    }
    public function unlockMakeup() {
        $this->_lockMakeup = false;
        return $this;
    }

    /**
     * Add action groups - special groups for action button
     * @param array|null $elements, if null, then auto add default elements (submit & reset button)
     * @param string $name
     * @param array|Zend_Config $options
     * @return Apps_Form
     */
    public function addActionGroup($elements=null, $name='form-action-group', $options=array()) {
        if(null === $elements) {
            $elementSubmit = new Zend_Form_Element_Submit(
            					     'submit',
                                     array(
                                         'label' => 'Save',
            						     'class' => 'btn btn-primary'
                                     )
                                 );
            $elementReset  = new Zend_Form_Element_Reset(
            						 'reset',
                                     array(
                                         'label' => 'Reset',
            						     'class' => 'btn'
                                     )
                                 );

            $elements = array($elementSubmit, $elementReset);
        }

        // Enable only ViewHelper decorator for this group elements
        foreach ($elements as $e) {
            if($e instanceof Zend_Form_Element
               && !$e->loadDefaultDecoratorsIsDisabled()) {
               $e->setDisableLoadDefaultDecorators(true)
                 ->setDecorators(array('ViewHelper'));
            }
        }

        $d = array(
                  array('decorator' => array('fe' => 'FormElements'),
                        'options'   => null),

                  array('decorator' => array('h' => 'HtmlTag'),
                        'options'    => array(
                                           'tag'   => 'div',
                                           'class' => $name))
              );

        if($options instanceof Zend_Config) { $options = $options->toArray(); }
        $options = array_merge(array('disableLoadDefaultDecorators' => true, 'decorators' => $d), $options);

        $this->addDisplayGroup($elements, $name, $options);

        $this->_actionGroups[] = $name;
        return $this;
    }
    public function clearActionGroups() {
        foreach ($this->_actionGroups as $name) {
            $f = $this->getDisplayGroup($name);
            foreach ($f->getElements() as $e) {
                $this->removeElement($e->getName());
            }
            $this->removeDisplayGroup($name);
        }
        return $this;
    }
    public function reloadActionGroups() {
        foreach ($this->_actionGroups as $name) {
            $g = $this->getDisplayGroup($name);
            $g->setOrder(1102);
        }
        return $this;
    }
    public function getDefaultActionGroup() {
        if(empty($this->_actionGroups)) {
            $this->addActionGroup();
        }
        $g = null;
        foreach ($this->_actionGroups as $g) {
            break;
        }
        return $this->getDisplayGroup($g);
    }

    /**
     * Make up the whole form
     * @return Apps_Form $this
     */
    public function makeup($bypassLockMakeup=false) {
        if(!$bypassLockMakeup && $this->_lockMakeup) { return $this; }

        $this->makeupForm()        		/* Form 			decorators */
             ->makeupDisplayGroups()    /* Display-Group 	decorators */
             ->makeupSubForms()    		/* Sub-Form 		decorators */
             ->makeupFormElements();    /* Form-Element 	decorators */

        return $this;
    }
    /**
     * Make up form only
     * @param bool $skipOnDecoratorsPreset
     * @return Apps_Form $this
     */
    public function makeupForm($skipOnDecoratorsPreset=true, $bypassLockMakeup=false) {
        if(!$bypassLockMakeup && $this->_lockMakeup) { return $this; }
        if($this->getDecorators() && $skipOnDecoratorsPreset) { return $this; }

        $decoratorForm = $this->getMakeupDecoratorForm();
        $this->setDecorators($decoratorForm);

        return $this;
    }

    /**
     * Make up display-groups only
     * @param bool $skipOnDisableDefaultDecoratorsLoad
     * @return Apps_Form $this
     */
    public function makeupDisplayGroups($skipOnDisableDefaultDecoratorsLoad=true, $bypassLockMakeup=false) {
        if(!$bypassLockMakeup && $this->_lockMakeup) { return $this; }

        $decoratorDisplayGroups = $this->getMakeupDecoratorFormDisplayGroups();

        foreach ($this->getDisplayGroups() as $d) {
            if($d->loadDefaultDecoratorsIsDisabled() && $skipOnDisableDefaultDecoratorsLoad) {
                continue;
            }

            $d->setDecorators($decoratorDisplayGroups);
        }

        return $this;
    }

    /**
    * Make up display-groups only
    * @param bool $skipOnDisableDefaultDecoratorsLoad
    * @return Apps_Form $this
    */
    public function makeupSubForms($skipOnDisableDefaultDecoratorsLoad=true, $bypassLockMakeup=false) {
        if(!$bypassLockMakeup && $this->_lockMakeup) {
            return $this;
        }

        $decoratorSubForms = $this->getMakeupDecoratorFormSubForms();

        foreach ($this->getSubForms() as $d) {
            if($d->loadDefaultDecoratorsIsDisabled() && $skipOnDisableDefaultDecoratorsLoad) {
                continue;
            }

            $d->setDecorators($decoratorSubForms);
        }

        return $this;
    }

    /**
     * Make up form-elements only
     * @param bool $skipOnDisableDefaultDecoratorsLoad
     * @return Apps_Form $this
     */
    public function makeupFormElements($skipOnDisableDefaultDecoratorsLoad=true, $bypassLockMakeup=false) {
        if(!$bypassLockMakeup && $this->_lockMakeup) { return $this; }

        $decoratorFormElements = $this->getMakeupDecoratorFormElements();

        foreach ($this->getElements() as $e) {
            if($e->loadDefaultDecoratorsIsDisabled() && $skipOnDisableDefaultDecoratorsLoad) {
                continue;
            }
            $e->setDecorators($decoratorFormElements);

            // If is File, replace viewHelper with File
            if($e instanceof Zend_Form_Element_File) {
                $e->addDecorator(array('v' => 'File'), null);
            }
        }

        return $this;
    }

    // HELPER
    public function getRequest() {
        if(!$this->_request) {
            $this->_request = Zend_Controller_Front::getInstance()->getRequest();
        }
        return $this->_request;
    }
    public function getResponse() {
        if(!$this->_response) {
            $this->_response = Zend_Controller_Front::getInstance()->getResponse();
        }
        return $this->_response;
    }
    public function __get($v) {
        $r = null;
        switch($v) {
            case '_request' :
                $r = $this->getRequest();
                break;
            case '_response' :
                $r = $this->getResponse();
                break;
            default :
                $r = parent::__get($v);
        }
        return $r;
    }
}